#include "HC_SR04.h"

extern uint32_t timeCount; // 引用计时溢出变量

/*经测试 误差0.03cm*/

/*
 *函数名称:HC_SR04_Init
 *函数功能:初始化超声波模块,TRIG--PA.6,ECHO--PA.7
 *参数:无
 *返回值:无
 *备  注:无
 */
void HC_SR04_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct;

  // GPIOA
  RCC_APB2PeriphClockCmd(HC_SR04_RCC_CLK, ENABLE);

  // 配置Trig引脚(PA.6)为推挽输出
  GPIO_InitStruct.GPIO_Pin = TRIG_PIN;
  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出
  GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(TRIG_PORT, &GPIO_InitStruct);

  // 配置ECHO引脚（PA.7）为浮空输入
  GPIO_InitStruct.GPIO_Pin = ECHO_PIN;
  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING; // 浮空输入
  GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(ECHO_PORT, &GPIO_InitStruct);

  GPIO_ResetBits(TRIG_PORT, TRIG_PIN); // Trig引脚初始化为低电平
  GPIO_ResetBits(ECHO_PORT, ECHO_PIN); // ECHO引脚初始化为低电平

  TIM3_Init(); // 初始化定时器TIM3
}

/*
 *函数名称:HC_SR04_MeasureDistance
 *函数功能:计算与障碍物的距离(cm)
 *参数:无
 *返回值:与障碍物的距离(cm)
 *备  注:如果没有没有测到距离会有2秒延时，则返回0
 */
float HC_SR04_MeasureDistance(void)
{
  float distance = -1.0; // 初始化距离为-1表示无效值
  float sum = 0;
  uint64_t high_time = 0; // 计算高电平时间
  uint32_t timeout;
  int i = 0;

  // 计算5次计算平均值
  while (i != 5)
  {
    // 产生一个10微秒的高电平脉冲以触发测距
    GPIO_SetBits(TRIG_PORT, TRIG_PIN);
    delay_us(20);
    GPIO_ResetBits(TRIG_PORT, TRIG_PIN);

    // 等待ECHO引脚变为高电平,设置超时时间为 2 秒
    timeout = 2000000; // 超时时间设置为 2 秒（2,000,000 微秒）

    // 等待ECHO引脚变为高电平
    while (!(GPIO_ReadInputDataBit(ECHO_PORT, ECHO_PIN)) && timeout > 0)
    {
      timeout--;
      delay_us(1);

      if (timeout == 0) // 计时器减为0
      {
        return 0;
      }
    }

    if (timeout > 0) // 如果没有超时
    {
      TIM3_Open(); // 开启定时器

      i++;

      timeout = 100000; // 重新设置超时时间

      // 等待ECHO引脚变为低电平
      while (GPIO_ReadInputDataBit(ECHO_PORT, ECHO_PIN) && timeout > 0)
      {
        timeout--;
        delay_us(1);
        if (timeout == 0) // 计时器减为0
        {
          return 0;
        }
        if (timeout == 0) // 计时器减为0
        {
          return 0;
        }
      }
    }

    TIM3_Close(); // 停止计时器

    high_time = TIM3_Count();

    // 计算距离（厘米）(声速：343m/s)
    distance = (float)((high_time * 0.034) / 2.0) * 1.03;

    sum += distance;
  }

  distance = sum / 5;

  return distance;
}
